# Copyright (c) 2009 Peter Corbett
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import random

import gamestate
import utils


class Magic:
    def __init__(self, pgprl, data, state):
        self.pgprl = pgprl
        self.state = state
        self.data = data
        self.edict = {"cure": self.cure_spell,
                      "blink": self.blink_spell,
                      "damage": self.damage_spell,
                      "status": self.status_spell,
                      "pstatus": self.pstatus_spell,
                      "destatus": self.destatus_spell,
                      "stealth": self.stealth_spell}
        self.tdict = {"self": self.target_self,
                      "bolt": self.target_bolt}
    def cast(self, caster, power, stype):
        targets = self.tdict[stype.target](caster, power, stype)
        if not targets:
            return False
        for t in targets:
            for effect in stype.effects:
                self.edict[effect.effect](caster, t, int(power * effect.pmult), effect)
        return True
    def test_resistance(self, caster, target):
        if caster == target or (not caster is self.state.pc and not target is self.state.pc) or (not isinstance(target, gamestate.Mob)):
            return False
        if random.randint(0,max(0,target.sdict["magdef"])) > random.randint(0, max(0,caster.sdict["maghit"])):
            v = "resist" if target is self.state.pc else "resists"
            self.pgprl.add_message("%s %s!" % (target.desc(self.data, "the", True), v))
            return True
        return False        
    def target_self(self, caster, power, stype):
        return (caster, )
    def target_bolt(self, caster, power, stype):
        if caster == self.state.pc:
            t = self.pgprl.target(True, "Select target for %s: " % stype.name)
            if not t:
                return None
            return (t, )
        else:
            if self.state.lostab[caster.x][caster.y]:
                return ((self.state.pc.x, self.state.pc.y), )
            else:
                return None
    def retarget_mob(self, target):
        if (type(target) is type(())) and len(target) == 2:
            target = self.state.current_level.passable(target[0], target[1], self.data, self.state.pc)
        return target
    def status_spell(self, caster, target, power, effect):
        target = self.retarget_mob(target)
        if isinstance(target, gamestate.Mob):
            if not self.test_resistance(caster, target):
                target.add_status(effect.dict["status"], power, self.data)
    def pstatus_spell(self, caster, target, power, effect):
        if isinstance(target, gamestate.Mob):
            if not self.test_resistance(caster, target):
                target.add_status(effect.dict["status"], None, self.data)
    def destatus_spell(self, caster, target, power, effect):
        target = self.retarget_mob(target)
        if isinstance(target, gamestate.Mob):
            if not self.test_resistance(caster, target):
                target.del_status(effect.dict["status"], self.data)
    def cure_spell(self, caster, target, power, effect):
        target = self.retarget_mob(target)
        if isinstance(target, gamestate.Mob):
            if target.hp == target.maxhp:
                return False
            target.hp = min(target.maxhp, target.hp+power)
            return True
        else:
            return False
    def damage_spell(self, caster, target, power, effect):
        target = self.retarget_mob(target)
        if isinstance(target, gamestate.Mob):
            if not self.test_resistance(caster, target):
                self.pgprl.resolve_hit(caster, target, int(power), True)
                return True
        else:
            return False
    def blink_spell(self, caster, target, power, effect):
        target = self.retarget_mob(target)
        if isinstance(target, gamestate.Mob):
            tiles = []
            for x in range(target.x - power, target.x + power + 1):
                for y in range(target.y - power, target.y + power + 1):
                    if self.state.current_level.passable(x, y, self.data, self.state.pc) == True:
                        tiles.append((x, y))
            if len(tiles) == 0:
                return False
            else:
                target.move_to(random.choice(tiles), self.state, self.data)
                #target.x, target.y = random.choice(tiles)
                return True
        else:
            return False
    def stealth_spell(self, caster, target, power, effect):
        if caster == self.state.pc:
            for mob in self.state.current_level.mobs:
                if self.state.lostab[mob.x][mob.y]:
                    self.pgprl.add_message("You can't start sneaking now!")
                    return False
            caster.add_status("stealth", None, self.data)
            return True
        else:
            # Trust the AI
            caster.add_status("stealth", None, self.data)

